from django.shortcuts import render,redirect
from django_redis import get_redis_connection
from decimal import Decimal
from django.http import JsonResponse,HttpResponseForbidden
import json
from django.utils import timezone
from django.db import transaction

from meiduo.utils.judgelogin import UserLoginView
from users.models import Addresses
from goods.models import *
from meiduo.utils.response_code import RETCODE
from payment.models import OrderGoods, OrderInfo


class PaymentShow(UserLoginView):
    """支付页面视图"""
    def get(self,request):
        user = request.user

        addresses = Addresses.objects.filter(user=user,is_deleted=False)
        # 地址数据

        conn = get_redis_connection(alias='carts')
        cart_dict_bite = conn.hgetall("carts_%d"%user.id)
        sku_id_all = conn.smembers("selected_%d"%user.id)
        if not sku_id_all:
            return redirect("/carts/")
        sku_qs = SKU.objects.filter(id__in=sku_id_all,is_launched=True)

        payment_amount = Decimal("0.00")
        total_count = 0
        for sku in sku_qs:
            sku.count = int(cart_dict_bite[str(sku.id).encode()])
            sku.amount = sku.count * sku.price
            payment_amount += sku.amount
            total_count += sku.count

        fright = Decimal("10.00")   # 运费
        context = {
            "addresses":addresses,
            "skus":sku_qs,
            "total_amount":payment_amount,
            "payment_amount":payment_amount + fright,
            "freight":fright,
            "total_count":total_count
        }
        return render(request,"place_order.html",context)


"""
redis中用户购物车数据结构
hash    carts_id: {sku_id:count,sku_id_2:count}
set   selected_id: {sku_id}  表示sku_id商品是否勾选
"""
"""
游客cookie保存数据结构
carts:  {
ku_id:{count:"",selected:""}
}
"""


class CommitOrderView(UserLoginView):
    """提交订单请求"""
    def post(self,request):
        # 接受数据
        user = request.user
        data_dict = json.loads(request.body.decode())
        address_id = data_dict.get("address_id")
        pay_method = data_dict.get("pay_method")
        # 校验数据
        if not all([address_id,pay_method]):
            return HttpResponseForbidden("参数错误")
        try:
            address = Addresses.objects.get(id=address_id,user=user,is_deleted=False)
        except Addresses.DoesNotExist:
            return HttpResponseForbidden("参数错误")
        try:
            pay_method = int(pay_method)
        except:
            return HttpResponseForbidden("参数错误")
        if pay_method not in [1,2]:
            return HttpResponseForbidden("参数错误")

        conn = get_redis_connection(alias='carts')
        pl = conn.pipeline()
        carts_dict_bite = conn.hgetall("carts_%d"%user.id)
        # 业务逻辑   事务  乐观锁
        # 订单信息  订单商品信息表中添加信息
        order_id = timezone.now().strftime("%Y%m%d%H%M%S")+"%09d"%user.id

        with transaction.atomic():
            save_point = transaction.savepoint()
            try:
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,   # 后面更改
                    total_amount=Decimal("0.00"),  #后面更改
                    freight=Decimal("10.00"),
                    pay_method=pay_method,
                    status= OrderInfo.ORDER_STATUS_ENUM["UNPAID"] if pay_method == OrderInfo.PAY_METHODS_ENUM["ALIPAY"] else OrderInfo.ORDER_STATUS_ENUM["UNCOMMENT"],
                )

                for sku_id in carts_dict_bite:
                    # 判断库存是否充足
                    i = 0
                    while True:
                        count = int(carts_dict_bite[sku_id])
                        sku_id = int(sku_id)
                        sku = SKU.objects.get(id=sku_id,is_launched=True)
                        stock = sku.stock     # 存量
                        if stock < count:
                            transaction.savepoint_rollback(save_point)  # 事务回滚
                            return JsonResponse({"code":RETCODE.STOCKERR,"errmsg":"%s库存不足"%sku.name})
                        # 订单商品信息表添加信息
                        order_good = OrderGoods.objects.create(
                            order_id=order_id,
                            sku=sku,
                            count=count,
                            price=sku.price,
                        )

                        result = SKU.objects.filter(id=sku_id,stock=stock,is_launched=True)
                        # 重查数据库信息  确认数据库信息未被更改  (乐观锁）
                        if not result:
                            i += 1  #
                            if i == 3:
                                return JsonResponse({"code": RETCODE.SERVERERR, "errmsg": "提交订单失败"})
                            continue
                        else:
                            break

                    # sku  spu 信息表中销量 库存修改
                    sku.stock -= count
                    sku.sales += count
                    sku.save()

                    spu = sku.spu
                    spu.sales += count
                    spu.save()

                    order.total_count += count
                    order.total_amount += count * sku.price

                order.total_amount += order.freight
                order.save()
            except:
                transaction.savepoint_rollback(save_point)   # 任何异常回滚
            else:
                transaction.savepoint_commit(save_point)  # 事务提交

        pl.delete("carts_%d"%user.id)
        pl.delete("selected_%d"%user.id)
        pl.execute()

        return JsonResponse({"code":RETCODE.OK,"errmsg":"OK","order_id":order_id})
"""
redis中用户购物车数据结构
hash    carts_id: {sku_id:count,sku_id_2:count}
set   selected_id: {sku_id}  表示sku_id商品是否勾选
"""


class CommitSuccessView(UserLoginView):
    def get(self,request):
        # 获取数据
        data_dict = request.GET
        order_id = data_dict.get("order_id")
        payment_amount = Decimal(data_dict.get("payment_amount"))
        pay_method = int(data_dict.get("pay_method"))
        # 校验数据
        try:
            OrderInfo.objects.get(order_id=order_id,total_amount=payment_amount,pay_method=pay_method)
        except OrderInfo.DoesNotExist:
            return HttpResponseForbidden("传入数据有误")

        context = {
            "order_id":order_id,
            "payment_amount":payment_amount,
            "pay_method":pay_method
        }
        return render(request,"order_success.html",context)
